package com.antler.luajavalibrary.luaext.utils;

import android.app.Instrumentation;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

public class TouchUtils {
    private static final String TAG = "antler_" + TouchUtils.class.getSimpleName();
    private static Instrumentation sInstrumentation = null;

    private TouchUtils() {
        throw new AssertionError();
    }

    private static Instrumentation getInstrumentation() {
        if (sInstrumentation == null) {
            sInstrumentation = new Instrumentation();
        }
        return sInstrumentation;
    }

    public static void down(int index, int x, int y) {

    }

    public static void move(int index, int x, int y) {

    }

    public static void up(int index, int x, int y) {

    }

    private static void injectMotionEvent(int action, long when, float x, float y, float pressure) {
        final float DEFAULT_SIZE = 1.0f;
        final int DEFAULT_META_STATE = 0;
        final float DEFAULT_PRECISION_X = 1.0f;
        final float DEFAULT_PRECISION_Y = 1.0f;
        final int DEFAULT_DEVICE_ID = 0;
        final int DEFAULT_EDGE_FLAGS = 0;
        MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
                DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID,
                DEFAULT_EDGE_FLAGS);
        getInstrumentation().sendPointerSync(event);
    }

    public static void tap(int x, int y) {
        long now = SystemClock.uptimeMillis();
        injectMotionEvent(MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
        injectMotionEvent(MotionEvent.ACTION_UP, now, x, y, 0.0f);
    }

    private static final float lerp(float a, float b, float alpha) {
        return (b - a) * alpha + a;
    }

    public void swipe(int x1, int y1, int x2, int y2, int duration) {
        if (duration < 0) {
            duration = 300;
        }

        long now = SystemClock.uptimeMillis();
        injectMotionEvent(MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
        long startTime = now;
        long endTime = startTime + duration;
        while (now < endTime) {
            long elapsedTime = now - startTime;
            float alpha = (float) elapsedTime / duration;
            injectMotionEvent(MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
                    lerp(y1, y2, alpha), 1.0f);
            now = SystemClock.uptimeMillis();
        }
        injectMotionEvent(MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
    }

    public static void press(int keyCode, boolean longPress) {
        long now = SystemClock.uptimeMillis();
        getInstrumentation().sendKeySync(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0));

        if (longPress) {
            getInstrumentation().sendKeySync(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS));
        }

        getInstrumentation().sendKeySync(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0));
    }

    public static void press(String keyName, boolean longPress) {
        int keyCode = KeyEvent.keyCodeFromString(keyName);
        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
            press(keyCode, longPress);
        } else {
            Log.e(TAG, "keyPress invalid keyName: " + keyName);
        }
    }

    public static void doublePress(int keyCode) {
        press(keyCode, false);

        getInstrumentation().waitForIdleSync();
        try {
            Thread.sleep(ViewConfiguration.getKeyRepeatDelay());
        } catch (InterruptedException e) {
            Log.e(TAG, "Could not sleep for long press timeout", e);
        }

        press(keyCode, false);
    }

    public static void doublePress(String keyName) {
        int keyCode = KeyEvent.keyCodeFromString(keyName);
        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
            doublePress(keyCode);
        } else {
            Log.e(TAG, "keyDown invalid keyName: " + keyName);
        }
    }
}
